﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "MainWndProcessCommandUtil.h"
#include "ICommand.h"
#include "UpdateCtrlStatusEvent.h"
#include "ICommandManager.h"
#include "JournalUtils.h"
#include "IJournalCommandData.h"
#include "IActionManager.h"
#include "IApplication.h"
#include "IUiDocumentViewManager.h"
#include "IMainWindow.h"
#include "IUiView.h"
#include "IAction.h"
#include "CommandParameters.h"
#include "InteractivePicker.h"
#include <QApplication>
#include <QMenu>
#include <qevent.h>
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;

namespace gcmp
{
    class CommandResourceHandler
    {
    public:
        CommandResourceHandler(const QObject* pObject) : m_isNeedReturn(false)
        {
            const QAction *pAction = dynamic_cast<const QAction*>(pObject);
            if (pAction && !m_sIsCommandExecuted)
            {
                //退出之前的命令
                IActionManager::Reset();
                //操纵器的事件循环退出比较特殊，需要满足条件ActionFinishReason::UserCustomReason，所以这里手动调用接口来强制结束InteractivePickerAction事件循环。IActionManager::Reset()只能结束InteractivePickerAction，并不能结束InteractivePickerAction内的EventLoop。
                InteractivePicker::EndCurrentInteractivePicker(ActionFinishStatus::Cancelled, ActionFinishReason::UserCustomReason);
                m_spAction = const_cast<QAction*>(pAction);
                m_isNeedReturn = true;
            }
            m_sIsCommandExecuted = false;
        }

        bool IsNeedReturn() const
        {
            return m_isNeedReturn;
        }

        static bool IsCommandExecuted()
        {
            return m_sIsCommandExecuted;
        }

        static void ExecuteCommand()
        {
            if (m_spAction)
            {
                QPoint point(1, 1);
                //如果命令没有执行完成，需要先退出上一个命令，再执行此命令
                QWidget* pWidget = m_spAction->parentWidget();
                QMenu* pMenu = dynamic_cast<QMenu*>(pWidget);
                //如果命令里的实现逻辑使用到了消息循环机制阻塞UI线程（如：InteractivePicker），需要先终止上一个命令，再启用新的命令
                //启用新的命令采用模拟用户点击按钮的qt事件
                //CheckBox和RadioButton等状态控件不会绑定命令，或者命令中一般不会使用阻塞机制，不需要处理
                if (pMenu)
                {
                    QRect rect = pMenu->actionGeometry(m_spAction);
                    point = rect.center();
                    pWidget = pMenu;
                }

                if (pWidget)
                {
                    QEvent *pMousePressEvent = NEW_AS_QT(QMouseEvent, QEvent::MouseButtonPress, point, Qt::MouseButton::LeftButton,
                        Qt::MouseButton::LeftButton, Qt::NoModifier);
                    QApplication::postEvent(pWidget, pMousePressEvent);

                    QEvent *pReleaseEvent = NEW_AS_QT(QMouseEvent, QEvent::MouseButtonRelease, point, Qt::MouseButton::LeftButton,
                        Qt::MouseButton::LeftButton, Qt::NoModifier);
                    QApplication::postEvent(pWidget, pReleaseEvent);
                }
                m_spAction = nullptr;
            }
        }

        ~CommandResourceHandler()
        {
            m_sIsCommandExecuted = true;
        }
    private:
        static bool m_sIsCommandExecuted;
        static QAction *m_spAction;
        bool m_isNeedReturn;
    };
    bool CommandResourceHandler::m_sIsCommandExecuted = true; //命令是否已经执行完成
    QAction* CommandResourceHandler::m_spAction = nullptr;

    void ProcessCommandUtil::ProcessRibbonBarCommand(const std::wstring& commandId, const gcmp::CommandParameters& commandParameters, const QObject* pSender)
    {
        IUiDocumentViewManager* pUiDocViewMgr = IUiDocumentViewManager::Get();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pUiDocViewMgr, L"pUiViewMgr为空",L"GDMPLab",L"2024-03-30");

        ICommand* pCommand = ICommandManager::Get()->GetCommand(commandId);
        if (pCommand != nullptr)
        {
            if (pCommand->HasCommandData())
            {
                OwnerPtr<gcmp::IJournalCommandData> opJournalCmdData = IJournalCommandData::Create();
                DBG_WARN_AND_RETURN_VOID_UNLESS(opJournalCmdData, L"CREATE_JOURNAL_DATA(IJournalCommandData, JOURNAL_COMMAND_DATA)返回空指针",L"GDMPLab",L"2024-03-30");
                opJournalCmdData->SetCommandName(pCommand->GetCommandId());
                JournalUtils::StartRecordCommand(TransferOwnership(opJournalCmdData));
            }
            else
            {
                OwnerPtr<gcmp::IJournalCommandData> opJournalCmdData = IJournalCommandData::Create();
                DBG_WARN_AND_RETURN_VOID_UNLESS(opJournalCmdData, L"CREATE_JOURNAL_DATA(IJournalCommandData, JOURNAL_COMMAND_DATA)返回空指针",L"GDMPLab",L"2024-03-30");
                opJournalCmdData->SetCommandName(pCommand->GetCommandId());
                opJournalCmdData->SetParameterArray(commandParameters);
                JournalUtils::RecordCommand(TransferOwnership(opJournalCmdData));
            }
            ICommandManager::Get()->SendCommand(commandId, commandParameters);
        }
        else
        {
            DBG_WARN(L"无法找到字符串对应的注册命令：" + commandId,L"GDMPLab",L"2024-03-30");
        }

        // 设置默认光标。
        IAction* pCurrentAction = IActionManager::CurrentAction();
        if (pCurrentAction)
        {
            if (IUiView* pCurrentView = pUiDocViewMgr->GetCurrentUiView())
                pCurrentView->SetCursorPath(pCurrentAction->GetCursorPath());
        }

        // 刷新界面。
        gcmp::OwnerPtr<UpdateCtrlStatusEvent> pEvent = NEW_AS_OWNER_PTR(UpdateCtrlStatusEvent);
        //IMainWindow* pMainWindow = IMainWindow::GetMainWindow();
        //DBG_WARN_AND_RETURN_VOID_UNLESS(pMainWindow, L"pMainWindowPrivate为空", L"GDMPLab", L"2023-12-20");
        //pMainWindow->PostEvent(TransferOwnership(pEvent));
        IApplication::Get()->PostEvent(TransferOwnership(pEvent));
        CommandResourceHandler::ExecuteCommand();
    }

    void ProcessCommandUtil::ProcessStatusBarCommand(const std::wstring& commandId, const gcmp::CommandParameters& commandParameters, const QObject* pSender)
    {
        CommandResourceHandler commandResourceHandler(pSender);
        if (commandResourceHandler.IsNeedReturn())
        {
            return;
        }
        ICommand* pCommand = ICommandManager::Get()->GetCommand(commandId);
        if (pCommand != nullptr)
        {
            gcmp::CommandParameters cmdParams;
            if (pCommand->HasCommandData())
            {
                OwnerPtr<gcmp::IJournalCommandData> opJournalCmdData = IJournalCommandData::Create();
                DBG_WARN_AND_RETURN_VOID_UNLESS(opJournalCmdData, L"CREATE_JOURNAL_DATA(IJournalCommandData, JOURNAL_COMMAND_DATA)返回空指针",L"GDMPLab",L"2024-03-30");
                opJournalCmdData->SetCommandName(pCommand->GetCommandId());
                JournalUtils::StartRecordCommand(TransferOwnership(opJournalCmdData));
            }
            else
            {
                OwnerPtr<gcmp::IJournalCommandData> opJournalCmdData = IJournalCommandData::Create();
                DBG_WARN_AND_RETURN_VOID_UNLESS(opJournalCmdData, L"CREATE_JOURNAL_DATA(IJournalCommandData, JOURNAL_COMMAND_DATA)返回空指针",L"GDMPLab",L"2024-03-30");
                opJournalCmdData->SetCommandName(pCommand->GetCommandId());
                opJournalCmdData->SetParameterArray(cmdParams);
                JournalUtils::RecordCommand(TransferOwnership(opJournalCmdData));
            }
            ICommandManager::Get()->SendCommand(commandId, cmdParams);
        }
        else
        {
            DBG_WARN(L"无法找到字符串对应的注册命令：" + commandId,L"GDMPLab",L"2024-03-30");
        }

        IMainWindow* pUIMainWnd = IMainWindow::GetMainWindow();

        // 刷新界面。
        gcmp::OwnerPtr<UpdateCtrlStatusEvent> pEvent = NEW_AS_OWNER_PTR(UpdateCtrlStatusEvent);
        IApplication::Get()->PostEvent(TransferOwnership(pEvent));
        CommandResourceHandler::ExecuteCommand();
    }

    bool ProcessCommandUtil::IsLastCommandExecuted()
    {
        return  CommandResourceHandler::IsCommandExecuted();
    }

}
